/**
 * 
 */

package com.shy.base.shiro;

import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;

import javax.annotation.Resource;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.context.annotation.Lazy;

import com.shy.portal.entity.Permission;
import com.shy.portal.entity.Role;
import com.shy.portal.entity.User;
import com.shy.portal.service.UserService;

/**
 * <p>
 * Title: UserRealm Shiro用户权限校驗核心类
 * </p>
 * <p>
 * Description:
 * </p>
 * <p>
 * Company:
 * </p>
 * 
 * @author H2013788
 */
public class UserRealm extends AuthorizingRealm {

    /**
     * 用户对应的角色信息与权限信息都保存在数据库中，通过UserService获取数据
     */
    @Resource
    //此處Lazy註解不可取消，取消后調用userService進行寫操作时事務失效异常
    @Lazy
    private UserService userService;
    
    @Resource
    private CacheManager shiroCacheManager;


    /**
     * 提供用户信息返回权限信息
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        ShiroUser shiroUser = (ShiroUser) principals.getPrimaryPrincipal();
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        User user = userService.getUserByName(shiroUser.getLoginName());
        // 根据用户名查询当前用户拥有的角色
        Set<Role> roles = new HashSet(userService.listRoleByUserId(user.getId()));
        Set<String> roleNames = new HashSet<String>();
        for (Role role : roles) {
            roleNames.add(role.getRoleCode());
        }
        // 根据用户名查询当前用户权限
        Set<Permission> permissions = new HashSet(userService.listPermissionByUserId(user.getId()));
        Set<String> permissionNames = new HashSet<String>();
        for (Permission permission : permissions) {
            permissionNames.add(permission.getPermissionCode());
        }
        // 将角色名称(code)提供给info
        authorizationInfo.setRoles(roleNames);
        // 将权限名称(code)提供给info
        authorizationInfo.setStringPermissions(permissionNames);
        return authorizationInfo;
    }

    /**
     * 登錄提供账户信息返回认证信息
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken)
            throws AuthenticationException {
        //UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
        EasyTypeToken token = (EasyTypeToken) authcToken;
        User user = userService.getUserByName(token.getUsername());
        if (user == null) {
            // 用户名不存在抛出异常
            throw new UnknownAccountException();
        }
        if (user.getStatus() == -1) {
            // 用户被管理员锁定抛出异常
            throw new LockedAccountException();
        }
        ShiroUser shiroUser = new ShiroUser(user.getId(), user.getUsername(), user.getRealname(), null);
        /*SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                user.getUsername(), user.getPassword(), ByteSource.Util.bytes(user
                        .getCredentialsSalt()), getName());*/
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                shiroUser, user.getPassword(), ByteSource.Util.bytes(user
                        .getCredentialsSalt()), getName());
        return authenticationInfo;
    }
    
    @Override
    protected Object getAuthenticationCacheKey(PrincipalCollection principals) {
        ShiroUser shiroUser = (ShiroUser) super.getAvailablePrincipal(principals);
        return shiroUser.toString();
    }

    @Override
    protected Object getAuthorizationCacheKey(PrincipalCollection principals) {
        ShiroUser shiroUser = (ShiroUser) super.getAvailablePrincipal(principals);
        return shiroUser.toString();
    }
    
    /**
     * 清除用户缓存
     * @param shiroUser
     */
    public void removeUserCache(ShiroUser shiroUser){
        SimplePrincipalCollection principals = new SimplePrincipalCollection();
        principals.add(shiroUser, getName());
        super.clearCachedAuthenticationInfo(principals);
        super.clearCachedAuthorizationInfo(principals);
    }

    /**
     * 清除用户缓存
     * @param loginName
     */
    public void removeUserCache(String loginName){
    	removeErrorLoginCache(loginName);
        SimplePrincipalCollection principals = new SimplePrincipalCollection();
        ShiroUser shiroUser = new ShiroUser(loginName);
        //principals.add(loginName, super.getName());
        //登錄驗證时，使用的shirouser，此處不可直接使用username
        principals.add(shiroUser, getName());
        super.clearCachedAuthenticationInfo(principals);
        super.clearCachedAuthorizationInfo(principals);
    }
    
    /**
     * 
     * 刪除登錄次数緩存
     * @author H2013788
     * @date 2019年8月12日
     */
    public void removeErrorLoginCache(String loginName) {
    	Cache<String, AtomicInteger> passwordRetryCache = shiroCacheManager.getCache("passwordRetryCache");
    	passwordRetryCache.remove(loginName); 
    }
    
}
